import pandas as pd
import numpy as np
from sklearn import tree
from sklearn.tree import DecisionTreeClassifier
from sklearn.linear_model import LogisticRegression
from sklearn.ensemble import RandomForestClassifier
from sklearn.preprocessing import MinMaxScaler
from sklearn.ensemble import RandomForestClassifier
from sklearn.cluster import KMeans
from sklearn.model_selection import train_test_split
from sklearn.model_selection import cross_val_score
from sklearn.utils import shuffle
from sklearn import metrics
import matplotlib.pyplot as plt
import seaborn as sns
import pydotplus

# 展示所有的列
pd.set_option('display.max_columns', None)
#读取数据
data = pd.read_excel('慢性肾病数据.xlsx', engine='openpyxl')[['性别', '遗传性肾脏病病史', '肾移植病史', '肾穿刺活检术史', '高血压病史', '糖尿病病史', '高尿血酸症', '肾脏超声发现构造异常', '尿常规蛋白指标', '尿白蛋白肌酐比', '血肌酐', 'eGFR', 'CKD分层']]

# 血肌酐分层
# 血肌酐的正常值：男性54.0~133.0μmol/L，女性44.0~97.0μmol/L，肾功能代偿期133~177μmol/L；肾功能失代偿期177~442μmol/L；肾功能衰竭期442~707μmol/L；尿毒症时＞707μmol/L；
# 血肌酐<133时，血肌酐=0，133≤血肌酐<177，血肌酐=1，177≤血肌酐<442，血肌酐=2，442≤血肌酐<707，血肌酐=4，血肌酐≥707，血肌酐=5
# EGFR分层
# 正常eGFR为≥90 ml/min/1.73m2；若eGFR< 60 ml/min/1.73m2则提示肾功能异常；若eGFR<15 ml/min/1.73m2则提示肾衰竭，需透析或肾移植治疗。
# eGFR≥90,eGFR=0,60≤eGFR<90,eGFR=1,15≤eGFR<60,eGFR=2,eGFR＜15,eGFR=3
# 尿蛋白肌酐比转换
# <30-0 30~300-1 >300-2
# 数据预处理
data = data.dropna()
data = data.replace({'男':1,'女':0,'有':1,'无':0,'是':1,'否':0,'阳性':1,'阴性':0,'<30':0,'30~300':1,'>300':2,'低危':0,'中危':1,'高危':2,'极高危':3})
#血肌酐替换 血肌酐<133，血肌酐=0，133≤血肌酐<177，血肌酐=1，177≤血肌酐<177，血肌酐=1，177≤血肌酐<442，血肌酐=2，442≤血肌酐<707，血肌酐=4，血肌酐≥707，血肌酐=5
data.loc[data['血肌酐'] < 133, '血肌酐'] = 0
data.loc[(data['血肌酐'] < 177) & (data['血肌酐'] >= 133), '血肌酐'] = 1
data.loc[(data['血肌酐'] < 442) & (data['血肌酐'] >= 177), '血肌酐'] = 2
data.loc[(data['血肌酐'] < 707) & (data['血肌酐'] >= 442), '血肌酐'] = 3
data.loc[data['血肌酐'] >= 707, '血肌酐'] = 4
#eGFR替换 eGFR≥90,eGFR=0,60≤eGFR<90,eGFR=1,15≤eGFR<60,eGFR=2,eGFR＜15,eGFR=3
data.loc[data['eGFR'] < 15, 'eGFR'] = 3
data.loc[(data['eGFR'] < 60) & (data['eGFR'] >= 15), 'eGFR'] = 2
data.loc[(data['eGFR'] < 90) & (data['eGFR'] >= 60), 'eGFR'] = 1
data.loc[data['eGFR'] >= 90, 'eGFR'] = 0
data = shuffle(data) #shuffle打乱数据集
data_sample = data[['性别', '遗传性肾脏病病史', '肾移植病史', '肾穿刺活检术史', '高血压病史', '糖尿病病史', '高尿血酸症', '肾脏超声发现构造异常', '尿常规蛋白指标', '尿白蛋白肌酐比', '血肌酐', 'eGFR']]
data_target = data['CKD分层']
print(data['eGFR'])
#print(data_sample)
#print(data_target)

# 拆分训练集测试集
Xtrain, Xtest, Ytrain, Ytest = train_test_split(data_sample, data_target, test_size=0.3)
print(Xtrain.shape)
print(Xtest.shape)

# 建立决策树和随机森林模型
clf = DecisionTreeClassifier(criterion="gini", max_depth=4)
rfc = RandomForestClassifier(n_estimators=20, criterion="gini", max_depth=4)
clf = clf.fit(Xtrain, Ytrain)
rfc = rfc.fit(Xtrain, Ytrain)
score_clf = clf.score(Xtest, Ytest)
score_rfc = rfc.score(Xtest, Ytest)
print(score_clf)
print(score_rfc)

# 画决策树图
dot_data = tree.export_graphviz(clf, out_file=None)
graph = pydotplus.graph_from_dot_data(dot_data)
graph.write_pdf("test.pdf")

# 调整max_depth,max_depth=4最佳
test_max_depth = []
for i in range(10):
    clf = tree.DecisionTreeClassifier(max_depth=i + 1
                                      , criterion="gini"
                                      , splitter="best"
                                      )
    clf = clf.fit(Xtrain, Ytrain)
    score = clf.score(Xtest, Ytest)
    test_max_depth.append(score)
plt.plot(range(1, 11), test_max_depth, color="red", label="max_depth")
plt.legend()
plt.show()


# 调整min_samples_split
test_min_samples_split = []
for i in range(2, 201):
    clf = tree.DecisionTreeClassifier(max_depth=4
                                      , criterion="gini"
                                      , splitter="best"
                                      , min_samples_split=i
                                      )
    clf = clf.fit(Xtrain, Ytrain)
    score = clf.score(Xtest, Ytest)
    test_min_samples_split.append(score)
plt.plot(range(2, 201), test_min_samples_split, color="red", label="min_samples_split")
plt.legend()
plt.show()


# 随机森林和决策树在一组交叉验证下的效果对比
rfc_s = cross_val_score(rfc, data_sample, data_target, cv=10)
clf_s = cross_val_score(clf, data_sample, data_target, cv=10)
plt.plot(range(1, 11), rfc_s, label="RandomForest")
plt.plot(range(1, 11), clf_s, label="Decision Tree")
plt.legend()
plt.show()



###逻辑回归分类
data = pd.read_excel('慢性肾病数据.xlsx', engine='openpyxl')[['性别', '遗传性肾脏病病史', '肾移植病史', '肾穿刺活检术史', '高血压病史', '糖尿病病史', '高尿血酸症', '肾脏超声发现构造异常', '尿常规蛋白指标', '尿白蛋白肌酐比', '血肌酐', 'eGFR', 'CKD分层']]


data = data.dropna()
data = data.replace({'男':1,'女':0,'有':1,'无':0,'是':1,'否':0,'阳性':1,'阴性':0,'<30':0,'30~300':1,'>300':2,'低危':0,'中危':1,'高危':2,'极高危':3})
data = shuffle(data)
#sns.pairplot(data=data, diag_kind='hist', hue='CKD分层')
#plt.show()


data_sample = data[['性别', '遗传性肾脏病病史', '肾移植病史', '肾穿刺活检术史', '高血压病史', '糖尿病病史', '高尿血酸症', '肾脏超声发现构造异常', '尿常规蛋白指标', '尿白蛋白肌酐比', '血肌酐', 'eGFR']]
data_target = data['CKD分层']
# MinMaxScaler缩放，移动数据使得所有特征都刚好位于0到1之间
minmax = MinMaxScaler(feature_range=(0.0, 1.0))
data_sample = minmax.fit_transform(data_sample)
print(data_sample)


Xtrain, Xtest, Ytrain, Ytest = train_test_split(data_sample, data_target, test_size=0.3)

train_score = []
test_score = []

'''
# 选择正则化参数C
for i in np.linspace(0.05, 3.5, 19):
    clr = LogisticRegression(solver='lbfgs', multi_class="multinomial", penalty="l2", C=i)
    clr.fit(Xtrain, Ytrain)
    train_predict = clr.predict(Xtrain)
    test_predict = clr.predict(Xtest)
    train_score.append(metrics.accuracy_score(Ytrain, train_predict))
    test_score.append(metrics.accuracy_score(Ytest, test_predict))
graph = [train_score, test_score]
color = ['red', 'green']
label = ['train', 'test']
plt.figure(figsize=(8, 6))
for i in range(len(graph)):
    plt.plot(np.linspace(0.05, 3.5, 19), graph[i], color[i], label=label[i])
plt.legend(loc=4)
plt.show()
'''
#查看混淆矩阵
clr = LogisticRegression(solver='lbfgs', multi_class="multinomial", penalty="l2", C=4)
clr.fit(Xtrain, Ytrain)
train_predict = clr.predict(Xtrain)
test_predict = clr.predict(Xtest)
print(metrics.accuracy_score(Ytrain, train_predict))
print(metrics.accuracy_score(Ytest, test_predict))
confusion_matrix_result = metrics.confusion_matrix(test_predict, Ytest)
plt.figure(figsize=(8, 6))
sns.heatmap(confusion_matrix_result, annot=True, cmap='Blues')
plt.xlabel('Predicted labels')
plt.ylabel('True labels')
plt.show()

###K-means聚类
data = pd.read_excel('慢性肾病数据.xlsx', engine='openpyxl')[['性别', '遗传性肾脏病病史', '肾移植病史', '肾穿刺活检术史', '高血压病史', '糖尿病病史', '高尿血酸症', '肾脏超声发现构造异常', '尿常规蛋白指标', '尿白蛋白肌酐比', '血肌酐', 'eGFR', 'CKD分层']]
data = data.dropna()
data = data.replace({'男':1,'女':0,'有':1,'无':0,'是':1,'否':0,'阳性':1,'阴性':0,'<30':0,'30~300':1,'>300':2,'低危':0,'中危':1,'高危':2,'极高危':3})
data = shuffle(data)
data_sample = data[['性别', '遗传性肾脏病病史', '肾移植病史', '肾穿刺活检术史', '高血压病史', '糖尿病病史', '高尿血酸症', '肾脏超声发现构造异常', '尿常规蛋白指标', '尿白蛋白肌酐比', '血肌酐', 'eGFR']]
minmax = MinMaxScaler(feature_range=(0.0, 1.0))
data_sample = minmax.fit_transform(data_sample)

#选择K值
SSE = []
for k in range(1, 20):
    km = KMeans(n_clusters=k, init='k-means++', random_state=0)
    km.fit(data_sample)
    SSE.append(km.inertia_)
plt.plot(range(1, 20), SSE, label='SSE')
plt.legend()
plt.show()